﻿using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using TcpJsonService.Core;

namespace TcpJsonService.Fvs
{
    /// <summary>
    /// 套接字发送结果
    /// </summary>
    public enum SocketResult
    {
        /// <summary>
        /// 发送成功
        /// </summary>
        Success = 0,
        /// <summary>
        /// 发送失败
        /// </summary>
        SendFailed = 1,
        /// <summary>
        /// 未找到套接字
        /// </summary>
        NotFoundSocket = 3
    }

    /// <summary>
    /// 收到控制器协议事件参数
    /// </summary>
    public class GotProtocolEventArgs : EventArgs
    {
        /// <summary>
        /// 本地监听端口
        /// </summary>
        public int Port { get; set; }

        /// <summary>
        /// 控制器编号
        /// </summary>
        public int ControllerId { get; set; }

        /// <summary>
        /// 协议编号
        /// </summary>
        public int ProtocolId { get; set; }

        /// <summary>
        /// 字节流
        /// </summary>
        public List<byte> Buffer { get; set; }
    }

    /// <summary>
    /// 控制器状态
    /// </summary>
    public class ControllerStatus
    {
        /// <summary>
        /// 控制器编号
        /// </summary>
        [SerializeIndex(1)]
        public int ControllerId { get; set; }

        /// <summary>
        /// 远程地址
        /// </summary>
        [SerializeIndex(2)]
        public uint RemoteIp { get; set; }

        /// <summary>
        /// 远程端口
        /// </summary>
        [SerializeIndex(3)]
        public ushort RemotePort { get; set; }

        /// <summary>
        /// 本地地址
        /// </summary>
        [SerializeIndex(4)]
        public uint LocalIp { get; set; }

        /// <summary>
        /// 本地端口
        /// </summary>
        [SerializeIndex(5)]
        public ushort LocalPort { get; set; }

        /// <summary>
        /// 发送总字节流
        /// </summary>
        [SerializeIndex(6)]
        public ulong Transmit { get; set; }

        /// <summary>
        /// 接收总字节流
        /// </summary>
        [SerializeIndex(7)]
        public ulong Receive { get; set; }

        /// <summary>
        /// 套接字
        /// </summary>
        public Socket Fd { get; set; }
    }

    /// <summary>
    /// 雾区网站控制器通道
    /// </summary>
    public class FvsControllerChannel : TcpChannel
    {
        /// <summary>
        /// 帧头
        /// </summary>
        private readonly byte _headTag;

        /// <summary>
        /// 本地监听端口
        /// </summary>
        private readonly int _port;

        /// <summary>
        /// 线程类
        /// </summary>
        private readonly Task _task;

        /// <summary>
        /// 线程取消功能
        /// </summary>
        private readonly CancellationTokenSource _source = new();

        /// <summary>
        /// 控制器字典,键为控制器编号
        /// </summary>
        private readonly ConcurrentDictionary<int, ControllerStatus> _controllers = [];

        /// <summary>
        /// 控制器响应事件
        /// </summary>
        public event EventHandler<GotProtocolEventArgs> Responsed;

        /// <summary>
        /// 控制器通知事件
        /// </summary>
        public event EventHandler<GotProtocolEventArgs> Noticed;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="port">本地监听端口</param>
        /// <param name="logger">日志</param>
        /// <param name="headTag">帧头</param>
        public FvsControllerChannel(int port, ILogger logger,byte headTag=0x90)
            : base(port, logger)
        {
            _port = port;
            _headTag = headTag;
            _task = new Task(GetControllerId, _source.Token);
            _task.Start();
        }

        /// <summary>
        /// 线程函数,确定控制器编号
        /// </summary>
        private void GetControllerId()
        {
            byte[] buffer = [0x81,0x7F, 0x11, 0xff];
            buffer = ToRealBuffer(buffer);
            while (!_source.IsCancellationRequested)
            {
                foreach (var socket in _accpetSockets)
                {
                    bool found = false;
                    foreach (var pair in _controllers)
                    {
                        if (socket.Key == pair.Value.Fd)
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        _logger.LogInformation($"=>c port:{_port} protocol:0x11 data:{ByteConvert.ToHex(buffer)}");
                        Send(socket.Key, buffer);
                        Thread.Sleep(1000);
                    }
                }
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 获取控制器状态集合
        /// </summary>
        /// <returns></returns>
        public List<ControllerStatus> GetStatus()
        {
            return [.. _controllers.Values];
        }

        /// <summary>
        /// 旧协议转新协议
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        protected virtual byte[] ToRealBuffer(byte[] buffer)
        {
            return buffer;
        }

        /// <summary>
        /// 新协议转就协议
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        protected virtual List<byte> ToCommonBuffer(List<byte> buffer)
        {
            return buffer;
        }

        /// <summary>
        /// 发送控制器协议
        /// </summary>
        /// <param name="controllerId">控制器编号</param>
        /// <param name="buffer">协议</param>
        public SocketResult SendProtocol(int controllerId, byte[] buffer)
        {
            if (buffer.Length < 4)
            {
                _logger.LogInformation($"send controller error port:{_port} id:{controllerId} data:{ByteConvert.ToHex(buffer)}");
                return SocketResult.SendFailed;
            }
            int protocolId = buffer[2];
            byte[] realBuffer = ToRealBuffer(buffer);
            if (_controllers.TryGetValue(controllerId, out ControllerStatus socket))
            {
                if (Send(socket.Fd, realBuffer))
                {
                    _controllers[controllerId].Transmit += Convert.ToUInt64(buffer.Length);
                    _logger.LogInformation($"=>c port:{_port} id:{controllerId} protocol:{protocolId:x2} data:{ByteConvert.ToHex(realBuffer)}");
                    return SocketResult.Success;
                }
                else
                {
                    _logger.LogInformation($"send controller failed port:{_port} id:{controllerId} protocol:{protocolId:x2} data:{ByteConvert.ToHex(realBuffer)}");
                    return SocketResult.SendFailed;
                }
            }
            else
            {
                _logger.LogInformation($"not found controller port:{_port} id:{controllerId} protocol:{protocolId:x2} data:{ByteConvert.ToHex(realBuffer)}");
                return SocketResult.NotFoundSocket;
            }
        }

        protected override bool Unpack(Socket socket, List<byte> buffer, ref int offset)
        {
            int head = buffer.FindIndex(offset, b => b == _headTag);
            //未找到协议
            if (head == -1)
            {
                offset += buffer.Count;
                return true;
            }
            else
            {
                //半包
                int tail = buffer.FindIndex(head, b => b == 0xFF);
                if (tail == -1)
                {
                    offset = head;
                    return false;
                }
                //整包
                else
                {
                    int packetSize = tail - head + 1;
                    Handle(socket, buffer.GetRange(head, packetSize));
                    offset += head + packetSize;
                    return true;
                }
            }
        }

        /// <summary>
        /// 处理控制器协议
        /// </summary>
        /// <param name="socket">套接字</param>
        /// <param name="buffer">字节流</param>
        private void Handle(Socket socket, List<byte> buffer)
        {
            if (buffer.Count < 4)
            {
                _logger.LogWarning($"got controller protocol error {ByteConvert.ToHex(buffer)}");
                return;
            }
            else
            {
                List<byte> commonBuffer= ToCommonBuffer(buffer);
                int controllerId = commonBuffer[1];
                int protocolId = commonBuffer[2];

                _logger.LogInformation($"c=> port:{_port} id:{controllerId} protocol:{protocolId:x2} data:{ByteConvert.ToHex(buffer)}");

                if (protocolId == 0x11)
                {
                    if (_controllers.TryGetValue(controllerId, out _))
                    {
                        if (_controllers[controllerId].Fd != socket)
                        {
                            _controllers[controllerId].Fd = socket;
                            _logger.LogInformation($"replace controller port:{_port} id:{controllerId} handle:{socket.Handle}");
                        }
                    }
                    else
                    {
                        ControllerStatus status = new()
                        {
                            ControllerId = controllerId,
                            RemoteIp = BitConverter.ToUInt32(((IPEndPoint)socket.RemoteEndPoint).Address.GetAddressBytes(), 0),
                            RemotePort = Convert.ToUInt16(((IPEndPoint)socket.RemoteEndPoint).Port),
                            LocalIp = BitConverter.ToUInt32(((IPEndPoint)socket.LocalEndPoint).Address.GetAddressBytes(), 0),
                            LocalPort = Convert.ToUInt16(((IPEndPoint)socket.LocalEndPoint).Port),
                            Fd = socket
                        };
                        _controllers.TryAdd(controllerId, status);
                        _logger.LogInformation($"add controller port:{_port} id:{controllerId} handle:{socket.Handle}");
                    }
                    return;
                }
                if (_controllers.TryGetValue(controllerId, out _))
                {
                    _controllers[controllerId].Receive += Convert.ToUInt64(buffer.Count);

                    if (protocolId == 0x06
                        || protocolId == 0x08
                        || protocolId == 0x10
                        || protocolId == 0x0a
                        || protocolId == 0x0c
                        || protocolId == 0x0e
                        || protocolId == 0x0a)
                    {
                        GotProtocolEventArgs args = new()
                        {
                            Port = _port,
                            ControllerId = controllerId,
                            ProtocolId=protocolId,
                            Buffer = commonBuffer
                        };
                        Noticed?.Invoke(this, args);
                    }
                    else
                    {
                        GotProtocolEventArgs args = new()
                        {
                            Port = _port,
                            ControllerId = controllerId,
                            ProtocolId = protocolId,
                            Buffer = commonBuffer
                        };
                        Responsed?.Invoke(this, args);
                    }
                }
            }
        }

        public override void Close()
        {
            _source.Cancel();
            try
            {
                _task.Wait(_source.Token);
            }
            catch (OperationCanceledException)
            {

            }
            base.Close();
        }
    }
}
